#ifndef __SHM_HPP__
#define __SHM_HPP__

#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>

std::string gpathname = ".";
int gproj_id = 0x66;
int gdefaultsize = 4096;
#define CREATER "creater"
#define USER "user"

// 共享内存
class SharedMemory
{
private:
	bool CreateHelper(int flg) // 创建共享内存
	{

		printf("形成键值成功: 0x%x\n", _key); // 键值的内容
		// 共享内存的生命周期随内核							//设置权限
		//_shmid = shmget(_key, _size, IPC_CREAT | IPC_EXCL | 0666);// 创建全新的(共享内存空间)shm
		_shmid = shmget(_key, _size, flg);
		if (_shmid < 0)
		{
			perror("shmget");
			return false;
		}
		printf("shmid: %d\n", _shmid);
		return true;
	}

	bool Create()
	{
		CreateHelper(IPC_CREAT | IPC_EXCL | 0666);
	}

	bool Attach()
	{
		_start_addr = shmat(_shmid, nullptr, 0);
		if ((long long)_start_addr == -1) // 64位环境下指针占8个字节，所以这里不能用int(4字节)会造成缺失
		{								  // 改为long long即为8字节
			perror("shmat");
			return false;
		}
		return true;
	}

	bool Get() // 获取共享内存--与创建只有一字之差
	{
		CreateHelper(IPC_CREAT);
	}

public:
	SharedMemory(const std::string &gpathname, int projid, 
		const std::string &usertype, int size = gdefaultsize)
		: _size(size), _key(0), _shmid(-1),
		  _start_addr(nullptr), _rindex(0), _windex(0), _num(0),
		  _usertype(usertype)
	{
		_key = ftok(gpathname.c_str(), gproj_id);
		if (_key < 0)
		{
			perror("ftok");
		}
		if (_usertype == CREATER)
			Create();
		else if (_usertype == USER)
			Get();
		else
		{
		}
		Attach();
	}

	void *VirtualAddr()
	{
		printf("VirtualAddr: %p\n", _start_addr);
		return _start_addr;
	}

	int Size()
	{
		return _size;
	}

	void AddChar(char ch)
	{
		if (_num == _size)
			return;
		((char *)_start_addr)[_windex++] = ch;

		_windex %= _size;
		_num++;
	}

	void Detach() // 分离（去关联）
	{			  // 参数：虚拟地址起始地址
		int n = shmdt(_start_addr);
		if (n == 0)
		{
			printf("detach success\n");
		}
	}

	void PopChar(char *ch)
	{
		if (_num == 0)
			return;
		*ch = ((char *)_start_addr)[_rindex++];
		_rindex %= _size;
		_num--;
	}

	bool RemoveShm()
	{
		Detach();
		if (_usertype == CREATER)
		{
			int n = shmctl(_shmid, IPC_RMID, nullptr);
			if (n < 0)
			{
				perror("shmctl");
				return false;
			}
			std::cout << "删除shm成功" << std::endl;
			return true;
		}
	}

	void Attr()
	{
		struct shmid_ds ds;
		int n = shmctl(_shmid, IPC_STAT, &ds);// ds:输出型参数
		printf("shm_segsz: %ld\n", ds.shm_segsz);
		printf("key: 0x%x\n", ds.shm_perm.__key);
	}

	~SharedMemory()
	{
		if (_usertype == CREATER)
			RemoveShm();
	}

private:
	key_t _key;
	int _size;
	int _shmid;
	void *_start_addr;
	int _num;
	int _rindex;
	int _windex;
	std::string _usertype;
};

#endif